home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / jput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-17  |  24.8 KB  |  946 lines

  1. /* 
  2.  * jput.c --
  3.  *
  4.  *    Perform a write on Jaquith archive system.
  5.  *
  6.  * Copyright 1991 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  * Quote:
  16.  *      "Action causes more trouble than thought."
  17.  *      -- Jenny Holzer
  18.  *
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/jput.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  23. #endif /* not lint */
  24.  
  25. #include "jaquith.h"
  26. #include "option.h"
  27. #include "jputInt.h"
  28.  
  29. int syserr;
  30. char **progOptions;
  31.  
  32. static void  CheckOptions     _ARGS_ ((Parms *parmsPtr));
  33. static int   CheckOneFile     _ARGS_ ((int sock, char *fileName,
  34.                        int recurse));
  35. static int   PutOneFile       _ARGS_ ((int sock, char *fileName,
  36.                        int recurse, int followLink,
  37.                        int cross));
  38. static int   PutOneFileStat   _ARGS_ ((int sock, struct stat *statPtr,
  39.                        char *fileName, char *abstract));
  40. static char *ListOneDirectory _ARGS_ ((char *dirName));
  41. static char *GetFileAbstract  _ARGS_ ((char *prog, char *progOptions,
  42.                        char *fileName));
  43. static char **ParseProgOptions _ARGS_ ((char *prog, char *options));
  44.  
  45. static char printBuf[T_MAXSTRINGLEN];
  46. static FILE *memDbg = NULL;
  47.  
  48. static uid_t myUid;
  49. static char *myName;
  50. static gid_t myGid;
  51. static char *myGroup;
  52. static gid_t rootUid;
  53.  
  54. static Parms parms = {
  55.     "",
  56.     -1,
  57.     "",
  58.     DEF_ABSTRACT,
  59.     DEF_ABSFILTER,
  60.     DEF_MAIL,
  61.     DEF_FORCE,
  62.     DEF_SYNC,
  63.     DEF_NEWVOL,
  64.     DEF_LOCAL,
  65.     DEF_RECURSE,
  66.     DEF_LINK,
  67.     DEF_VERBOSE,
  68.     DEF_MODTIME,
  69.     DEF_MODTIMEVAL,
  70.     DEF_ABSFILTEROPT,
  71.     DEF_PRUNE,
  72.     DEF_PRUNEPATH,
  73.     DEF_IGNORE,
  74.     DEF_CROSS,
  75.     DEF_ACKFREQ
  76. };
  77.  
  78. Option optionArray[] = {
  79.     {OPT_STRING, "server", (char *)&parms.server, "Server hostname"},
  80.     {OPT_INT, "port", (char *)&parms.port, "Port of server"},
  81.     {OPT_STRING, "arch", (char *)&parms.arch, "Logical archive name"},
  82.     {OPT_STRING, "mail", (char *)&parms.mail, "Mail address"},
  83.     {OPT_STRING, "abs", (char *)&parms.abstract, "Text abstract"},
  84.     {OPT_STRING, "absfilter", (char *)&parms.absFilter, "Program to generate text abstract"},
  85.     {OPT_STRING, "absfilteropt", (char *)&parms.absFilterOpt, "Options for abstract filter program"},
  86.     {OPT_TRUE, "link", (char *)&parms.link, "Follow symbolic links"},
  87.     {OPT_TRUE, "v", (char *)&parms.verbose, "Verbose"},
  88.     {OPT_STRING, "mod", (char *)&parms.modTime, "Put files modified since date"},
  89.     {OPT_CONSTANT(T_FORCE), "force", (char *)&parms.force, "Force files to archive, even if not modified since last archived"},
  90.     {OPT_CONSTANT(T_SYNC), "sync", (char *)&parms.sync, "Write data to volume synchronously"},
  91.     {OPT_CONSTANT(T_NEWVOL), "newvol", (char *)&parms.newvol, "Start a new volume. The -sync option is required"},
  92.  
  93.     {OPT_CONSTANT(T_LOCAL), "local", (char *)&parms.local, "File system is local to server"},
  94.  
  95.     {OPT_TRUE, "dir", (char *)&parms.recurse, "Put directory and top-level contents only"},
  96. /*
  97.     {OPT_TRUE, "filter", (char *)&parms.filter, "Run filter on file before archiving it."},
  98.     {OPT_TRUE, "filteropt", (char *)&parms.filterOpt, "Options for filter program"},
  99. */
  100.     {OPT_STRING, "prune", (char *)&parms.prune, "Don't archive subtrees whose simple name matches globbing expression"},
  101.     {OPT_STRING, "prunepath", (char *)&parms.prunePath, "Don't archive subtrees whose full path name matches globbing expression"},
  102.     {OPT_STRING, "ignore", (char *)&parms.ignore, "Don't archive and don't record files whose name matches globbing expression"},
  103.     {OPT_TRUE, "crossremote", (char *)&parms.cross, "Cross over remote link boundaries (Sprite systems only)"},
  104.     {OPT_INT, "ackfreq", (char *)&parms.ackFreq, "Acknowledge every Nth file"}
  105. };
  106. int numOptions = sizeof(optionArray) / sizeof(Option);
  107.  
  108.  
  109. /*
  110.  *----------------------------------------------------------------------
  111.  *
  112.  * main --
  113.  *
  114.  *    Main driver for jput program.
  115.  *
  116.  * Results:
  117.  *    none.
  118.  *
  119.  * Side effects:
  120.  *    Sends requests across socket to Jaquith server.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124.  
  125. int
  126. main(argc, argv)
  127. int argc;
  128. char *argv[];
  129. {
  130.     int sock;
  131.     int retCode;
  132.     int i;
  133.     T_RespMsgHdr resp;
  134.     char defaultName = '\0';
  135.     char *defaultList = &defaultName;
  136.     char **nameList = &defaultList;
  137.     char *fileName;
  138.     int nameCnt = 1;
  139.     static T_FileStat dummyFile =
  140.     {"", "", "", "", "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  141.  
  142. /*    memDbg = fopen("jput.mem", "w"); */
  143.     MEM_CONTROL(8192, memDbg, TRACEMEM+TRACECALLS+CHECKALLBLKS, 4096);
  144.  
  145.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  146.  
  147.     CheckOptions(&parms);
  148.  
  149.     sock = Sock_SetupSocket(parms.port, parms.server, 1);
  150.  
  151.     Sock_SendReqHdr(sock, T_CMDPUT, 0, parms.mail,  parms.arch,
  152.             (parms.force | parms.sync | parms.newvol | parms.local));
  153.  
  154.     /* Announce acknowledgement frequency */
  155.     if (Sock_WriteInteger(sock, parms.ackFreq) != T_SUCCESS) {
  156.     sprintf(printBuf, "Couldn't send ack frequency. Errno %d\n", syserr);
  157.     Utils_Bailout(printBuf, BAIL_PRINT);
  158.     }
  159.  
  160.     /* get ok to proceed */
  161.     Sock_ReadRespHdr(sock, &resp);
  162.     if (resp.status != T_SUCCESS) {
  163.     fprintf(stdout,"%s", Utils_MakeErrorMsg(resp.status, resp.errno));
  164.     close(sock);
  165.     exit(-1);
  166.     }
  167.  
  168.     if (argc > 1) {
  169.     nameCnt = argc-1;
  170.     nameList = &argv[1];
  171.     }
  172.  
  173.     /*
  174.      * For each item in list, conditionally put out an entry for
  175.      * all the parts leading up to it.
  176.      */
  177.     for (i=0; i<nameCnt; i++) {
  178.         fileName = Utils_MakeFullPath(nameList[i]);
  179.     if (((*parms.prunePath) && (Str_Match(fileName, parms.prunePath))) ||
  180.         ((*parms.prune) && (Str_Match(nameList[i], parms.prune)))) {
  181.         fprintf(stderr,"Warning: pruning top-level item: %s\n",
  182.             nameList[i]);
  183.     } else if ((!*parms.ignore) ||
  184.            (!Str_Match(nameList[i], parms.ignore))) {
  185.         retCode = CheckOneFile(sock, fileName, parms.recurse);
  186.         MEM_FREE("jput", fileName);
  187.     }
  188.     }
  189.  
  190.     /* Put end of list marker */
  191.     Sock_WriteFileStat(sock, &dummyFile, 0);
  192.  
  193.     /* see what happened */
  194.     Sock_ReadRespHdr(sock, &resp);
  195.     if (resp.status != T_SUCCESS) {
  196.     fprintf(stdout,"%s", Utils_MakeErrorMsg(resp.status, resp.errno));
  197.     }
  198.  
  199.     close(sock);
  200.  
  201.     MEM_REPORT("jput", ALLROUTINES, SORTBYREQ);
  202.  
  203.     return(0);
  204.  
  205. }
  206.  
  207.  
  208. /*
  209.  *----------------------------------------------------------------------
  210.  *
  211.  * CheckOneFile -- 
  212.  *
  213.  *    Write a single file's meta info over socket and get response
  214.  *
  215.  * Results:
  216.  *    Error if file not found or sock dies.
  217.  *
  218.  * Side effects:
  219.  *    none.
  220.  *
  221.  *----------------------------------------------------------------------
  222.  */
  223.  
  224. static int
  225. CheckOneFile(sock, fileName, recurse)
  226.     int sock;                 /* outgoing socket */
  227.     char *fileName;           /* full name of file */
  228.     int recurse;              /* recursion flag */
  229. {
  230.     struct stat unixStatBuf;
  231.     char partName[T_MAXPATHLEN];
  232.     int retCode;
  233.     char **partList;
  234.     int partCnt;
  235.     int i;
  236.     char *insidePtr;
  237.  
  238.     if (strlen(fileName) > T_MAXPATHLEN) {
  239.     fprintf(stderr, "%s: pathname exceeds %d characters.\n",
  240.         fileName, T_MAXPATHLEN);
  241.     return T_FAILURE;
  242.     }
  243.     if (parms.link) {
  244.     retCode = stat(fileName, &unixStatBuf);
  245.     } else {
  246.     retCode = lstat(fileName, &unixStatBuf);
  247.     }
  248.     if (retCode < 0) {
  249.     perror(fileName);
  250.     return errno;
  251.     }
  252.  
  253.     if ((!S_ISADIR(unixStatBuf.st_mode)) &&
  254.     (*(fileName+strlen(fileName)-1) == '/')) {
  255.     fprintf(stderr,"%s: not a directory\n", fileName);
  256.     return T_FAILURE;
  257.     }
  258.  
  259.     if (Time_Compare(unixStatBuf.st_mtime, parms.modTimeVal, 0) <= 0) {
  260.     return T_SUCCESS;
  261.     }
  262.  
  263.     /*
  264.      * put out all the directories leading up to the file
  265.      */
  266.     partList = Str_Split(fileName, '/', &partCnt, 0, &insidePtr);
  267.     retCode = PutOneFile(sock, "/", 0, 0, 0);
  268.     for (i=1,*partName='\0'; i<partCnt-1; i++) {
  269.     strcat(partName, "/");
  270.     strcat(partName, partList[i]);
  271.     retCode = PutOneFile(sock, partName, 0, 1, 0);
  272.     }
  273.  
  274.     retCode = PutOneFile(sock, fileName, parms.recurse, parms.link, 1);
  275.     MEM_FREE("jput", partList);
  276.     MEM_FREE("jput", (char *)insidePtr);
  277.  
  278.     return retCode;
  279. }
  280.  
  281.  
  282.  
  283. /*
  284.  *----------------------------------------------------------------------
  285.  *
  286.  * PutOneFile -- 
  287.  *
  288.  *    Write a single file's name and contents out over socket.
  289.  *
  290.  * Results:
  291.  *    Error if file not found or sock dies.
  292.  *
  293.  * Side effects:
  294.  *    none.
  295.  *
  296.  * Note:
  297.  *      This algorithm is horrid. Presently we are sending the current
  298.  *      file metadata to the server which does a comparison with the
  299.  *      metadata stored in the index. The server then returns a 
  300.  *      "do or don't archive" flag to tell us whether to send the
  301.  *      file or not. What we should be doing is just issuing a standard
  302.  *      jls-style command for the file and doing the comparison ourselves.
  303.  *
  304.  *----------------------------------------------------------------------
  305.  */
  306.  
  307. static int
  308. PutOneFile(sock, fileName, recurse, followLink, cross)
  309.     int sock;                 /* outgoing socket */
  310.     char *fileName;           /* full name of file */
  311.     int recurse;              /* recursion flag */
  312.     int followLink;           /* follow symbolic links */
  313.     int cross;                /* cross remote links (Sprite only) */
  314. {
  315.     int retCode;
  316.     int fileStream;
  317.     char *abstract;
  318.     char buf[T_BUFSIZE];
  319.     DIR *dirStream;
  320.     DirObject *entryPtr;
  321.     char newName[2*T_MAXPATHLEN];
  322.     int newLen;
  323.     int readCnt;
  324.     int len;
  325.     int size;
  326.     int type;
  327.     struct stat unixStatBuf;
  328.     char *newNamePtr = newName;
  329.     int dontArchive = 0;
  330.     char nullByte = '\0';
  331.     static int filesSinceAck = 0;
  332.  
  333.     MEM_REPORT("jput", ALLROUTINES, SORTBYREQ);
  334.  
  335.     if (followLink) {
  336.     retCode = stat(fileName, &unixStatBuf);
  337.     } else {
  338.     retCode = lstat(fileName, &unixStatBuf);
  339.     }
  340.     if (retCode == -1) {
  341.     sprintf(printBuf, "%s: Stat failed", fileName);
  342.     perror(printBuf);
  343.     return retCode;
  344.     }
  345.     if ((myUid != rootUid) &&
  346.     (access(fileName, R_OK) != 0)) {
  347.     fprintf(stdout, "%s: permission denied.\n", fileName);
  348.     unixStatBuf.st_size = 0; /* put out a dummy file */
  349.     } 
  350.     if (*parms.absFilter) {
  351.     abstract = GetFileAbstract(parms.absFilter, progOptions, fileName);
  352.     } else {
  353.     abstract = parms.abstract;
  354.     }
  355.  
  356.     if ((retCode=PutOneFileStat(sock, &unixStatBuf, fileName, abstract))
  357.     != T_SUCCESS) {
  358.     return retCode;
  359.     }
  360.  
  361.     if (!parms.force) {
  362.     if (Sock_ReadString(sock, &newNamePtr, 0) != T_SUCCESS) {
  363.         sprintf(printBuf, "%s: server name confirmation failed\n",
  364.             fileName);
  365.         Utils_Bailout(printBuf, BAIL_PRINT); 
  366.     }
  367.     if (strcmp(newNamePtr, fileName) != 0) {
  368.         sprintf(printBuf, "expected name '%s' != '%s'\n",
  369.             fileName, newNamePtr);
  370.         Utils_Bailout(printBuf, BAIL_PRINT);
  371.     }
  372.     if (Sock_ReadInteger(sock, &dontArchive) != T_SUCCESS) {
  373.         sprintf(printBuf, "%s: server go-ahead confirmation failed\n",
  374.             fileName);
  375.         Utils_Bailout(printBuf, BAIL_PRINT);
  376.     }
  377.     if ((dontArchive != 0) && (dontArchive != 1)) {
  378.         sprintf(printBuf, "go-ahead for %s is strange: %d\n",
  379.             fileName, dontArchive);
  380.         Utils_Bailout(printBuf, BAIL_PRINT);
  381.     }
  382.     }
  383.  
  384.     if ((!dontArchive) && (parms.verbose)) {
  385.     printf("%s %d\n", fileName, unixStatBuf.st_size);
  386.     }
  387.     if ((!dontArchive) &&
  388.     (!parms.local) &&
  389.     ((int)unixStatBuf.st_size > 0)) {
  390.     size = (int)unixStatBuf.st_size;
  391.     if ((fileStream=open(fileName, O_RDONLY, 0)) == -1) {
  392.         perror(fileName);
  393.         strncpy(buf, &nullByte, sizeof(buf));
  394.         while (size > 0) {
  395.         len = (size > sizeof(buf)) ? sizeof(buf) : size;
  396.         if (Sock_WriteNBytes(sock, buf, len) != len) {
  397.             exit(-1);
  398.         }
  399.         size -= len;
  400.         }
  401.         return T_IOFAILED;
  402.     }
  403.     
  404.     while (size > 0) {
  405.         len = (size > sizeof(buf)) ? sizeof(buf) : size;
  406.         if ((readCnt=Sock_ReadNBytes(fileStream, buf, len)) > 0) {
  407.         if (Sock_WriteNBytes(sock, buf, readCnt) != readCnt) {
  408.             fprintf(stderr,"Connection to server died.\n");
  409.             exit(-1);
  410.         }
  411.         size -= readCnt;
  412.         } else {
  413.         break;
  414.         }
  415.     }
  416.     
  417.     /*
  418.      * If didn't complete, print message and send zeros
  419.      */
  420.     if (size > 0) {
  421.         fprintf(stderr,"PutOneFile: short %d bytes for '%s'. errno %d\n",
  422.             size, fileName, errno);
  423.         strncpy(buf, &nullByte, sizeof(buf));
  424.         while (size > 0) {
  425.         len = (size > sizeof(buf)) ? sizeof(buf) : size;
  426.         if (Sock_WriteNBytes(sock, buf, len) != len) {
  427.             exit(-1);
  428.         }
  429.         size -= len;
  430.         }
  431.     }
  432.     close(fileStream);
  433.     }
  434.  
  435.     /*
  436.      * Time to wait for ack ?
  437.      */
  438.     if (parms.ackFreq > 0) {
  439.     if (++filesSinceAck >= parms.ackFreq) {
  440.         Sock_ReadString(sock, &newNamePtr, 0);
  441.         if (strcmp(newName, fileName) != 0) {
  442.         Utils_Bailout("Ack failed:\n\tGot %s\n\tExpected %s\n",
  443.                   newName, fileName);
  444.         }
  445.         filesSinceAck = 0;
  446.     }
  447.     }
  448.  
  449.     /*
  450.      * If this file is a directory (or we are crossing remote links)
  451.      * and we're dumping recursively, we have more work to do.
  452.      */
  453.     type = unixStatBuf.st_mode & S_IFMT;
  454.     if ((recurse > 0) &&
  455.     ((type == S_IFDIR) || (cross && (type == S_IFRLNK)))) {
  456.     if ((dirStream=opendir(fileName)) == (DIR *)NULL) {
  457.         return T_IOFAILED;
  458.     }
  459.     recurse--;
  460.     strcpy(newName, fileName);
  461.     newLen = strlen(newName);
  462.     *(newName+newLen++) = '/';
  463.     while ((entryPtr=readdir(dirStream)) != (DirObject *)NULL) {
  464.         strcpy(newName+newLen, entryPtr->d_name);
  465.         if ((strcmp(entryPtr->d_name, ".") == 0) ||
  466.         (strcmp(entryPtr->d_name, "..") == 0) ||
  467.         (Str_Match(entryPtr->d_name, parms.ignore)) ||
  468.         ((*parms.prunePath)&&(Str_Match(newName, parms.prunePath))) ||
  469.         ((*parms.prune)&&(Str_Match(entryPtr->d_name, parms.prune)))) {
  470.           continue;
  471.         }
  472.         retCode = PutOneFile(sock, newName, recurse,
  473.                  followLink, parms.cross);
  474.     }
  475.     closedir(dirStream);
  476.     }
  477.     
  478.     return retCode;
  479.  
  480. }
  481.  
  482.  
  483. /*
  484.  *----------------------------------------------------------------------
  485.  *
  486.  * PutOneFileStat -- 
  487.  *
  488.  *    Write a single file's status info
  489.  *
  490.  * Results:
  491.  *    None.
  492.  *
  493.  * Side effects:
  494.  *    Modifies size field to tell caller not to dump data.
  495.  *
  496.  *----------------------------------------------------------------------
  497.  */
  498.  
  499. static int
  500. PutOneFileStat(sock, unixStatPtr, fileName, abstract)
  501.     int sock;                 /* outgoing socket */
  502.     struct stat *unixStatPtr; /* outgoing metadata */
  503.     char *fileName;           /* outgoing complete file path */
  504.     char *abstract;           /* outgoing abstract */
  505. {
  506.     T_FileStat statInfo;
  507.     int retCode;
  508.     int  type = unixStatPtr->st_mode & S_IFMT; 
  509.     char linkName[T_MAXPATHLEN];
  510.     char null = '\0';
  511.     static Hash_Handle *uidHandle = (Hash_Handle *)NULL;
  512.     static Hash_Handle *gidHandle = (Hash_Handle *)NULL;
  513.     char *uname;
  514.     char *gname;
  515.  
  516.     if (uidHandle == (Hash_Handle *) NULL) {
  517.     uidHandle = Hash_Create("login", 59, Utils_StringHashProc, 1);
  518.     gidHandle = Hash_Create("group", 59, Utils_StringHashProc, 1);
  519.     }
  520.  
  521.     if (Hash_Lookup(uidHandle, (Hash_Key)&unixStatPtr->st_uid,
  522.             sizeof(unixStatPtr->st_uid),
  523.             (Hash_ClientData *)&uname) == T_FAILURE) {
  524.     uname = Utils_GetLoginByUid(unixStatPtr->st_uid);
  525.     Hash_Insert(uidHandle, (Hash_Key)&unixStatPtr->st_uid,
  526.             sizeof(unixStatPtr->st_uid), (Hash_ClientData)uname);
  527.     }
  528.     if (Hash_Lookup(gidHandle, (Hash_Key)&unixStatPtr->st_gid,
  529.             sizeof(unixStatPtr->st_gid),
  530.             (Hash_ClientData *)&gname) == T_FAILURE) {
  531.     gname = Utils_GetGroupByGid(unixStatPtr->st_gid);
  532.     Hash_Insert(gidHandle, (Hash_Key)&unixStatPtr->st_gid,
  533.             sizeof(unixStatPtr->st_gid), (Hash_ClientData)gname);
  534.     }
  535.  
  536.     statInfo.fileName = fileName;
  537.     statInfo.linkName = linkName;
  538.     statInfo.uname = uname;
  539.     statInfo.gname = gname;
  540.     statInfo.abstract = abstract;
  541.     statInfo.fileList = &null;
  542.  
  543.     if (!S_ISREG(type)) {
  544.     unixStatPtr->st_size = 0;
  545.     }
  546.     if (S_ISADIR(type)) {
  547.     statInfo.fileList = ListOneDirectory(fileName);
  548.     }
  549.     if (S_ISALNK(type)) {
  550.     linkName[readlink(fileName, linkName, T_MAXPATHLEN)] = '\0';
  551.     /* This is a tar restriction */
  552.     if (strlen(linkName) > LINKNAMELEN) {
  553.         fprintf(stderr, "%s: truncating link name to %d chars.\n",
  554.             fileName, LINKNAMELEN);
  555.         strcpy(linkName+LINKNAMELEN-10, ".truncated");
  556.     }
  557.     } else {
  558.     *linkName = '\0';
  559.     }
  560.  
  561.     statInfo.size = unixStatPtr->st_size;
  562.     statInfo.atime = unixStatPtr->st_atime;
  563.     statInfo.mtime = unixStatPtr->st_mtime;
  564.     statInfo.volId = 0;
  565.     statInfo.filemark = 0;
  566.     statInfo.tBufId = 0;
  567.     statInfo.offset = 0;
  568.     statInfo.uid = (int) unixStatPtr->st_uid;
  569.     statInfo.gid = (int) unixStatPtr->st_gid;
  570.     statInfo.mode = unixStatPtr->st_mode;
  571.     statInfo.vtime = 0;
  572.     if ((type == S_IFCHR) || (type == S_IFBLK)) {
  573.     statInfo.rdev = unixStatPtr->st_rdev;
  574.     } else {
  575.     statInfo.rdev = 0;
  576.     }
  577.     
  578.     retCode = Sock_WriteFileStat(sock, &statInfo, 0);
  579.  
  580.     if (S_ISADIR(type)) {
  581.     MEM_FREE("PutOneFileStat", statInfo.fileList);
  582.     }
  583.  
  584.     return(retCode);
  585.  
  586. }
  587.  
  588.  
  589.  
  590. /*
  591.  *----------------------------------------------------------------------
  592.  *
  593.  * ListOneDirectory --
  594.  *
  595.  *    Form a string of filename in a directory.
  596.  *
  597.  * Results:
  598.  *    None.
  599.  *
  600.  * Side effects:
  601.  *      None.
  602.  *
  603.  *----------------------------------------------------------------------
  604.  */
  605.  
  606. static char *
  607. ListOneDirectory(dirName)
  608. char *dirName;
  609. {
  610.     DIR *dirStream;
  611.     DirObject *entryPtr;
  612.     int cnt = 0;
  613.     int i = 0;
  614.     char *bufPtr;
  615.     char *namePtr;
  616.     int nameLen;
  617.     char **nameArray;
  618.     int totLen = 1;
  619.  
  620.     if ((dirStream=opendir(dirName)) == (DIR *)NULL) {
  621.     return Str_Dup("");
  622.     }
  623.  
  624.     while ((entryPtr=readdir(dirStream)) != (DirObject *)NULL) {
  625.     if ((strcmp(entryPtr->d_name, ".") != 0) &&
  626.         (strcmp(entryPtr->d_name, "..") != 0) &&
  627.         (Str_Match(entryPtr->d_name, parms.ignore) == 0)) {
  628.         cnt++;
  629.     }
  630.     }
  631.  
  632.     if (cnt == 0) {
  633.         closedir(dirStream);
  634.     return Str_Dup("");
  635.     }
  636.  
  637.     nameArray = (char **)MEM_ALLOC("ListOneDirectory",cnt*sizeof(char *));
  638.  
  639.     rewinddir(dirStream);
  640.     
  641.     while (i < cnt) {
  642.     if ((entryPtr=readdir(dirStream)) == (DirObject *)NULL) {
  643.         break;
  644.     }
  645.     nameLen = strlen(entryPtr->d_name) + 1;
  646.     if ((strcmp(entryPtr->d_name, ".") != 0) &&
  647.         (strcmp(entryPtr->d_name, "..") != 0) &&
  648.         (Str_Match(entryPtr->d_name, parms.ignore) == 0)) {
  649.         nameArray[i] = MEM_ALLOC("ListOneDirectory", nameLen);
  650.         strcpy(nameArray[i], entryPtr->d_name);
  651.         totLen += nameLen;
  652.         i++;
  653.     }
  654.     }
  655.  
  656.     closedir(dirStream);
  657.  
  658.     bufPtr = namePtr = (char *)MEM_ALLOC("ListOneDirectory", totLen);
  659.  
  660.     for (cnt=0; cnt < i; cnt++) {
  661.     strcpy(namePtr,nameArray[cnt]);
  662.     nameLen = strlen(nameArray[cnt]);
  663.     namePtr += nameLen;
  664.     *namePtr++ = ' ';
  665.     MEM_FREE("ListOneDirectory", nameArray[cnt]);
  666.     }
  667.     *(namePtr-1) = '\0';
  668.  
  669.     MEM_FREE("ListOneDirectory", (char *)nameArray);
  670.  
  671.     return bufPtr;
  672. }
  673.  
  674.  
  675. /*
  676.  *----------------------------------------------------------------------
  677.  *
  678.  * ReportError --
  679.  *
  680.  *    Translate error into reasonable msg
  681.  *
  682.  * Results:
  683.  *    none.
  684.  *
  685.  * Side effects:
  686.  *    none.
  687.  *
  688.  *----------------------------------------------------------------------
  689.  */
  690.  
  691. static void
  692. ReportError(status, errno)
  693. int status;
  694. int errno;
  695. {
  696.     /* This is all temporary */
  697.     char *msg = "?????";
  698.     char *msgPtr;
  699.  
  700.     if ((errno < 0) || (errno > sys_nerr)) {
  701.     msgPtr = msg;
  702.     } else {
  703.     msgPtr = sys_errlist[errno];
  704.     }
  705.     fprintf(stderr,"status = %d. errno = %d\n%s\n",
  706.         status, errno, msgPtr);
  707. }
  708.  
  709.  
  710.  
  711. /*
  712.  *----------------------------------------------------------------------
  713.  *
  714.  * CheckOptions -- 
  715.  *
  716.  *    Make sure command line options look reasonable
  717.  *
  718.  * Results:
  719.  *    none.
  720.  *
  721.  * Side effects:
  722.  *    Will set global variable progOptions if -absfilteropt is given.
  723.  *
  724.  *----------------------------------------------------------------------
  725.  */
  726.  
  727. static void
  728. CheckOptions(parmsPtr)
  729. Parms *parmsPtr;
  730. {
  731.     struct timeb timeB1;
  732.     char *envPtr;
  733.  
  734.     if ((!*parmsPtr->arch) &&
  735.     ((envPtr=getenv(ENV_ARCHIVE_VAR)) != (char *)NULL)) {
  736.     parmsPtr->arch = envPtr;
  737.     }
  738.     if ((*parmsPtr->arch) &&
  739.     (Utils_CheckName(parmsPtr->arch, 1) == T_FAILURE)) {
  740.     sprintf(printBuf,
  741.         "Bad archive name: '%s'.\nUse -arch or set %s environment variable.\n",
  742.         parmsPtr->arch, ENV_ARCHIVE_VAR);
  743.     Utils_Bailout(printBuf, BAIL_PRINT);
  744.     }
  745.     if ((!*parmsPtr->server) &&
  746.     ((parmsPtr->server=getenv(ENV_SERVER_VAR)) == (char *)NULL)) {
  747.     parmsPtr->server = DEF_SERVER;
  748.     }
  749.     if (Utils_CheckName(parmsPtr->server, 1) == T_FAILURE) {
  750.     sprintf(printBuf,
  751.         "Bad server name: '%s'.\nUse -server or set %s environment variable.\n",
  752.         parmsPtr->server, ENV_SERVER_VAR);
  753.     Utils_Bailout(printBuf, BAIL_PRINT);
  754.     }
  755.     if (parmsPtr->port == -1) {
  756.     if ((envPtr=getenv(ENV_PORT_VAR)) == (char *)NULL) {
  757.         parmsPtr->port = DEF_PORT;
  758.     } else {
  759.         Utils_CvtInteger(envPtr, 1, SHRT_MAX, &parmsPtr->port);
  760.     }
  761.     }
  762.     if ((parmsPtr->port < 1) || (parmsPtr->port > SHRT_MAX)) {
  763.     sprintf(printBuf,
  764.         "Bad port number %d.\nUse -port or set %s environment variable\n",
  765.         parmsPtr->port, ENV_PORT_VAR);
  766.     Utils_Bailout(printBuf, BAIL_PRINT);
  767.     }
  768.     if ((*parmsPtr->mail) && 
  769.     (Utils_CheckName(parmsPtr->mail, 1) != T_SUCCESS)) {
  770.     sprintf(printBuf, "Bad mail address: '%s'\n", parmsPtr->mail);
  771.     Utils_Bailout(printBuf, BAIL_PRINT);
  772.     }
  773.     if (strlen(parmsPtr->abstract) > T_MAXSTRINGLEN) {
  774.     sprintf(printBuf,"Abstract cannot exceed %d chars.", T_MAXSTRINGLEN);
  775.     Utils_Bailout(printBuf, BAIL_PRINT);
  776.     }
  777.     if ((*parmsPtr->abstract) && (*parmsPtr->absFilter)) {
  778.     Utils_Bailout("Can't supply both -abs and -absfilter options.",
  779.               BAIL_PRINT);
  780.     }
  781.     if ((!*parmsPtr->absFilter) && (*parmsPtr->absFilterOpt)) {
  782.     Utils_Bailout("Need -absfilter option with -absfilteropt.",
  783.               BAIL_PRINT);
  784.     }
  785.     if ((progOptions=ParseProgOptions(parmsPtr->absFilter,
  786.                       parmsPtr->absFilterOpt)) == NULL) {
  787.      Utils_Bailout("Couldn't parse -absfilteropt argument.", BAIL_PRINT);
  788.     }
  789.     if (strcmp(parmsPtr->modTime, DEF_MODTIME) != 0) {
  790.     if (getindate(parmsPtr->modTime, &timeB1) != T_SUCCESS) {
  791.         Utils_Bailout("Need date in format: 20-Mar-1980:10:20:0",
  792.             BAIL_PRINT);
  793.     }
  794.     parmsPtr->modTimeVal = timeB1.time;
  795.     }
  796.     if ((parmsPtr->newvol) && (!parmsPtr->sync)) {
  797.     Utils_Bailout("Need -sync option with -newvol option.", BAIL_PRINT);
  798.     }
  799.     if (parmsPtr->ackFreq < 0) {
  800.     Utils_Bailout("Argument for -ackfreq must be positive.", BAIL_PRINT);
  801.     }
  802.  
  803.     myUid = geteuid();
  804.     myName = Utils_GetLoginByUid(myUid);
  805.     myGid = getegid();
  806.     myGroup = Utils_GetGroupByGid(myGid);
  807.     rootUid = Utils_GetUidByLogin(ROOT_LOGIN);
  808.     if ((parmsPtr->local) && (myUid != rootUid)) {
  809.     sprintf(printBuf, "Must be %s to use -local option\n", ROOT_LOGIN);
  810.     Utils_Bailout(printBuf, BAIL_PRINT);
  811.     }
  812.     MEM_FREE("CheckOptions", myName);
  813.  
  814. }
  815.  
  816.  
  817.  
  818. /*
  819.  *----------------------------------------------------------------------
  820.  *
  821.  * GetFileAbstract --
  822.  *
  823.  *    Invoke child program to generate abstract.
  824.  *
  825.  * Results:
  826.  *      static character string.
  827.  *
  828.  * Side effects:
  829.  *    Spawns child and reads data from child's stdout.
  830.  *
  831.  *----------------------------------------------------------------------
  832.  */
  833.  
  834. static char *
  835. GetFileAbstract(prog, progOptions, fileName)
  836.     char *prog;
  837.     char **progOptions;
  838.     char *fileName;
  839. {
  840.     static char buf[16*1024]; /* arbitrary limit */
  841.     int pipeStreams[20];
  842.     int val;
  843.     int total = 0;
  844.     int remaining = sizeof(buf)-1;
  845.     char *ptr = buf;
  846.  
  847.     *buf = '\0';
  848.  
  849.     if (pipe(pipeStreams) < 0) {
  850.     return buf;
  851.     } 
  852.  
  853.     if ((val=fork()) < 0) {
  854.     return buf;
  855.     } else if (val == 0) {
  856.     MEM_CONTROL(0, NULL, 0, 0);
  857.     close(pipeStreams[0]);
  858.     close(1);
  859.     dup(pipeStreams[1]);
  860.     progOptions[1] = fileName;
  861.     execvp(prog, progOptions);
  862.     fprintf(stderr,"child: exec returned\n");
  863.     _exit(-1);
  864.     } else {
  865.     close(pipeStreams[1]);
  866.     while ((remaining > 0) &&
  867.            (val=read(pipeStreams[0], ptr, remaining)) > 0) {
  868.         total += val;
  869.         remaining -= val;
  870.         ptr += val;
  871.     }
  872.     close(pipeStreams[0]);
  873.     *(buf+total) = '\0';
  874.     }
  875.  
  876.     return buf;
  877. }
  878.  
  879.  
  880.  
  881. /*
  882.  *----------------------------------------------------------------------
  883.  *
  884.  * ParseProgOptions --
  885.  *
  886.  *    Break up user's callback program options.
  887.  *
  888.  * Results:
  889.  *      static array of part ptrs. 
  890.  *
  891.  * Side effects:
  892.  *    Directly munges the options argument
  893.  *
  894.  *----------------------------------------------------------------------
  895.  */
  896.  
  897. static char **
  898. ParseProgOptions(prog, options)
  899.     char *prog;               /* name of program */
  900.     char *options;            /* option string */
  901. {
  902.     static char *progOptions[100];
  903.     static char matchGroup[]  = "\"'`";
  904.     char *matchPtr;
  905.     int count = 2;
  906.     char *ptr = options;
  907.  
  908.     progOptions[0] = prog;
  909. /*  progOptions[1] = will be the file jput needs an abstract for */
  910.  
  911.     while (1) {
  912.     while ((*ptr) && (isspace(*ptr))) {
  913.         ptr++;
  914.     }
  915.     if (!*ptr) {
  916.         break;
  917.     }
  918.     if (count >= 100) {
  919.         Utils_Bailout("Too complex: -absfilteropt argument.", BAIL_PRINT);
  920.     }
  921.     progOptions[count++] = ptr;
  922.     if ((matchPtr=STRCHR(matchGroup, *ptr++)) == NULL) {
  923.         while ((*ptr) && (!isspace(*ptr))) {
  924.         ptr++;
  925.         }
  926.     } else {
  927.         while ((*ptr) && (*ptr != *matchPtr)) {
  928.         ptr++;
  929.         }
  930.         if (!*ptr++) {
  931.         Utils_Bailout("Mismatched group in -absfilteropt argument.",
  932.             BAIL_PRINT);
  933.         }
  934.     }
  935.     if (!*ptr) {
  936.         break;
  937.     }
  938.     *ptr++ = '\0';
  939.     }
  940.  
  941.     progOptions[count] = NULL;
  942.  
  943.     return progOptions;
  944. }
  945.  
  946.